﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
using Aeon.Presentation;

namespace Aeon.Emulator.Launcher
{
    /// <summary>
    /// Displays emulation statistics.
    /// </summary>
    public partial class PerformanceWindow : Window
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the PerformanceWindow class.
        /// </summary>
        public PerformanceWindow()
        {
            InitializeComponent();
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets or sets the current EmulatorDisplay control.
        /// </summary>
        public EmulatorDisplay EmulatorDisplay { get; set; }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Invoked when the window is initialized.
        /// </summary>
        /// <param name="e">Unused EventArgs object.</param>
        protected override void OnInitialized(EventArgs e)
        {
            timer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, timer_Tick, this.Dispatcher);
            timer.Start();

            base.OnInitialized(e);
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Updates processor information in the window.
        /// </summary>
        /// <param name="host">Current EmulatorHost instance.</param>
        private void UpdateProcessorFields(EmulatorHost host)
        {
            long currentCount = host.TotalInstructions;
            if(currentCount < lastCount)
                lastCount = 0;

            ips.Enqueue(currentCount - lastCount);
            if(ips.Count > 10)
                ips.Dequeue();

            var average = ips.Average();

            instructionsLabel.Content = currentCount.ToString("#,#");
            ipsLabel.Content = average.ToString("#,#");

            lastCount = currentCount;
        }
        /// <summary>
        /// Updates memory information in the window.
        /// </summary>
        /// <param name="host">Current EmulatorHost instance.</param>
        private void UpdateMemoryFields(EmulatorHost host)
        {
            var conventionalMemory = host.VirtualMachine.GetConventionalMemoryUsage();
            conventionalMemoryLabel.Content = string.Format("{0}k used, {1}k free", conventionalMemory.MemoryUsed / 1024, conventionalMemory.MemoryFree / 1024);

            var expandedMemory = host.VirtualMachine.GetExpandedMemoryUsage();
            expandedMemoryLabel.Content = string.Format("{0}k used, {1}k free", expandedMemory.BytesAllocated / 1024, expandedMemory.BytesFree / 1024);

            var extendedMemory = host.VirtualMachine.GetExtendedMemoryUsage();
            extendedMemoryLabel.Content = string.Format("{0}k used, {1}k free", extendedMemory.BytesAllocated / 1024, extendedMemory.BytesFree / 1024);
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Invoked once every second to update values.
        /// </summary>
        /// <param name="sender">Source of event.</param>
        /// <param name="e">Unused EventArgs object.</param>
        private void timer_Tick(object sender, EventArgs e)
        {
            var display = this.EmulatorDisplay;
            if(display != null)
            {
                var host = display.EmulatorHost;
                if(host != null)
                {
                    if(processorExpander.IsExpanded)
                        UpdateProcessorFields(host);

                    if(memoryExpander.IsExpanded)
                        UpdateMemoryFields(host);
                }
            }
        }
        #endregion

        #region Private Fields
        private readonly Queue<long> ips = new Queue<long>();
        private long lastCount;
        private DispatcherTimer timer;
        #endregion
    }
}
